package cn.springcloud.fix.common.core.utils.json;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.type.MapType;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
public class JsonUtil {

    private static final ObjectMapper mapper = new ObjectMapper();

    static {
        mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        // 对象的所有字段全部列入
        mapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
        // 取消默认转换timestamps形式
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        // 忽略空bean转json的错误
        mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        // 统一日期格式
        mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        // 忽略在json字符串中存在, 但在java对象中不存在对应属性的情况, 防止错误
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

    public static <T> String objToStr(T object) {
        try {
            if (object == null) return null;
            return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(object);
        } catch (JsonProcessingException e) {
            log.error(e.getMessage(), e);
            return null;
        }
    }

    public static <T> T strToObj(String str, Class<T> clazz) {
        try {
            if (StringUtils.isBlank(str) || null == clazz) {
                return null;
            }
            return mapper.readValue(str, clazz);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return null;
        }
    }

    public static <T> T strToObj(String str, TypeReference<T> typeReference) {
        try {
            if (StringUtils.isBlank(str) || null == typeReference) {
                return null;
            }
            return mapper.readValue(str, typeReference);
        } catch (Exception e) {
            log.error("strToObj error", e);
            return null;
        }
    }

    public static <T> T toBean(String json, Class<T> clazz) {
        try {
            return mapper.readerFor(clazz).readValue(json);
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            return null;
        }
    }

    public static <E> List<E> toList(String json, Class<E> clazz) {
        try {
            JavaType javaType = mapper.getTypeFactory().constructParametricType(ArrayList.class, clazz);
            return mapper.readValue(json, javaType);
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException();
        }
    }

    public static <K, V> Map<K, V> toMap(String json) {
        try {
            MapType mapType = mapper.getTypeFactory().constructRawMapType(Map.class);
            return mapper.readValue(json, mapType);
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException();
        }
    }

    public static <K, V> Map<K, V> toMap(String s, Class<K> keyClass, Class<V> valueClass) {
        try {
            JavaType valueType = mapper.getTypeFactory().constructMapType(HashMap.class, keyClass, valueClass);
            return mapper.readValue(s, valueType);
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException();
        }
    }

    public static Map<String, Object> beanToMap(Object object) {
        Map<String, Object> map = new HashMap<>();
        if (object == null) return map;
        Field[] fields = object.getClass().getDeclaredFields();
        for (Field field : fields) {
            try {
                field.setAccessible(true);
                map.put(field.getName(), field.get(object));
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }
        return map;
    }

    /*public static void main(String[] args) {
        List<String> list = toList("[1,2,3,4,5]", String.class);
        list.forEach(item -> {
            System.out.println(item + 1);
        });
    }*/
}
